/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __HMFS_COMMON_H__
#define __HMFS_COMMON_H__

#include <memory>
#include <string>
#include <sys/stat.h>
#include "hmfs_data.h"
#include "hmfs_define.h"
#include "hmfs_command.h"

namespace OHOS::Hmfs {

/*
 * For directory operations
 */

#define LINUX_S_IFMT  00170000
#define LINUX_S_IFREG  0100000
#define LINUX_S_ISREG(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFREG)

#define DEF_DIR_LEVEL        0

#define HMFS_COMPR_FL        0x00000004 /* Compress file */

/* 200 bytes for inline xattrs by default */
#define DEFAULT_INLINE_XATTR_ADDRS    50
#define DEF_ADDRS_PER_INODE    923    /* Address Pointers in an Inode */
#define CUR_ADDRS_PER_INODE(inode)    (DEF_ADDRS_PER_INODE - GetExtraIsize(inode))

#define FS_IMMUTABLE_FL        0x00000010 /* Immutable file */

#define ALIGN_DOWN(addrs, size)    (((addrs) / (size)) * (size))
#define ALIGN_UP(addrs, size)    ALIGN_DOWN(((addrs) + (size) - 1), (size))

/*
 * Copied from include/linux/kernel.h
 */
#define __round_mask(x, y)    ((__typeof__(x))((y)-1))
#define round_down(x, y)      ((x) & ~__round_mask(x, y))
#define round_up(x, y)        (((x) + (y) - 1) / (y))

class HmfsCommon {
public:
    HmfsCommon(CmdConfig &cfgPara) : cfgPara_(cfgPara) {};

    static HmfsCommon& GetInstance();
    static void CreateInstance(CmdConfig &cfgPara);

    int LogBase2(uint32_t num);
    int GetBitsInByte(unsigned char n);
    int TestAndSetBitLe(uint32_t nr, uint8_t *addr);
    int TestAndClearBitLe(uint32_t nr, uint8_t *addr);
    int TestBitLe(uint32_t nr, const uint8_t *addr);

    int HmfsTestBit(unsigned int nr, const char *p);
    int HmfsSetBit(unsigned int nr, char *addr);
    int HmfsClearBit(unsigned int nr, char *addr);

    uint64_t FindNextBitLe(const uint8_t *addr, uint64_t size, uint64_t offset);
    uint64_t FindNextZeroBitL(const uint8_t *addr, uint64_t size, uint64_t offset);

    uint32_t DentryHash(int encoding, int casefolded, const unsigned char *name, int len);

    unsigned int AddrsPerInode(HmfsInode *i);
    unsigned int AddrsPerBlock(HmfsInode *i);
    unsigned int HmfsMaxFileOffset(HmfsInode *i);

    uint32_t HmfsCalCrc32(uint32_t crc, void *buf, int len);
    int HmfsCrcValid(uint32_t blk_crc, void *buf, int len);
    uint32_t HmfsInodeChksum(NodeData *node, uint32_t crcSeed);
    uint32_t HmfsCheckpointChksum(CheckPointData *cp);
    int WriteInode(NodeData *inode, uint64_t blkaddr, uint32_t crcSeed);

    void HmfsInitConfiguration(void);
    int HmfsDevIsWritable(void);
    int HmfsDevIsUmounted(char *path);
    int HmfsDevsAreUmounted(void);
    void GetKernelVersion(uint8_t *version);
    void GetKernelUnameVersion(uint8_t *version);
    int32_t GetKernelVersion(char *buf, size_t len);    // 替换掉上面两个函数以及HmfsIo::DevReadVersion
    bool KernelVersionOver(uint32_t minMajor, uint32_t minMinor);
    bool HmfsHasExtraIsize(struct HmfsInode *inode);
    int GetInlineXattrAddrs(struct HmfsInode *inode);

    unsigned int CalcExtraIsize(void);
    void InitQfInode(NodeData *rawNode, uint32_t inodeId, time_t mtime);
    inline uint64_t GetCpCrc(struct CheckPointData *cp)
    {
        uint64_t cpVersion = GetLeValue(cp->cpVersion);
        size_t crcOffset = GetLeValue(cp->checksumOffset);
        uint32_t crc = LE32_TO_NATIVE(*(uint32_t *)((unsigned char *)cp + crcOffset));
        cpVersion |= ((uint64_t)crc << 32);
        return NATIVE_TO_LE64(cpVersion);
    }
    int GetExtraIsize(HmfsInode* inode);
    int IsPowerOf2(unsigned long n);
    double GetBestOverProvision(SuperBlockData* superBlock);
    std::vector<std::string> SplitStringList(const std::string& srcString, char delimiter);

private:
    static std::unique_ptr<HmfsCommon> instance_;
    CmdConfig& cfgPara_;

    static uint64_t Ffs(uint8_t word);
    static uint64_t FindNextBitLeFunc(const uint8_t *addr, uint64_t nbits, uint64_t start, char invert);

    std::unique_ptr<char[]> GetRootdev();
#ifdef HAVE_SETMNTENT
    static int IsMounted(const char *mpt, const char *device);
#endif

    int32_t ReadKernelVersion(const std::string& path, char* buf, size_t len);

};
} // namespace OHOS::Hmfs
#endif